using System;
using System.Collections.Generic;
using System.Text;
using Evolution.Engine.Interfaces;
using System.Collections;
using Microsoft.Xna.Framework;
using System.Collections.ObjectModel;
using Evolution.Engine.Managers;

namespace Evolution.Engine.SpatialTrees
{
    public class ShaderTree : ISpatialTree
    {
        private Dictionary<string, Dictionary<string, BaseObject>> _Groups = new Dictionary<string, Dictionary<string, BaseObject>>();
        private Dictionary<string, Collection<BaseObject>> _DrawList = new Dictionary<string, Collection<BaseObject>>();

        public BaseObject Find(string Name)
        {
            return null;
        }
        
        public ScenenodeCollection Nodes()
        {
            return null;
        }
        
        public void Add(BaseObject newObject)
        {
            if (!_Groups.ContainsKey(newObject.Shader))
                _Groups.Add(newObject.Shader, new Dictionary<string,BaseObject>());

            if( !_Groups[newObject.Shader].ContainsKey(newObject.Name))
                _Groups[newObject.Shader].Add(newObject.Name, newObject);
        }

        public void Clear()
        {
            foreach (KeyValuePair<string, Dictionary<string, BaseObject>> group in _Groups)
                group.Value.Clear();
            _Groups.Clear();
        }

        #region ISpatialTree Members

        public void Update(GameTime gameTime)
        {
            _DrawList.Clear();
            foreach (KeyValuePair<string, Dictionary<string, BaseObject>> group in _Groups)
            {
                foreach (KeyValuePair<string, BaseObject> obj in group.Value)
                {
                    obj.Value.Update(gameTime);

                    obj.Value.Visible = false;
                    if (obj.Value is IRenderable ||
                        obj.Value is IChildRenderer) obj.Value.Visible = CameraManager.Instance.ActiveCamera.Frustum.Contains(obj.Value.Bounds) == ContainmentType.Disjoint;

                    if (obj.Value.Visible)
                    {
                        if (!_DrawList.ContainsKey(obj.Value.Shader))
                            _DrawList.Add(obj.Value.Shader, new Collection<BaseObject>());

                        _DrawList[obj.Value.Shader].Add(obj.Value);
                    }
                }
            }
        }

        public void Draw(GameTime gameTime)
        {
            foreach (Collection<BaseObject> group in _DrawList.Values)
            {                
                for (int i = 0; i < group.Count; i++)
                {
                    group[i].Draw(gameTime);
                }
            }
        }

        private Matrix GetWorldMatrix(ref BaseObject myObject)
        {
            if (!myObject.AlwaysFacingPlayer)
            {
                return Matrix.CreateScale(myObject.Scale) *
                       Matrix.CreateFromQuaternion(myObject.Rotation) *
                       Matrix.CreateTranslation(myObject.Position);
            }
            else
            {
                return Matrix.CreateScale(myObject.Scale) *
                       Matrix.CreateFromQuaternion(CameraManager.Instance.ActiveCamera.Rotation * -1) *
                       Matrix.CreateTranslation(myObject.Position);
            }
        }

        #endregion

        #region ISpatialTree Members


        public void LoadContent()
        {
            foreach (KeyValuePair<string, Dictionary<string, BaseObject>> group in _Groups)
            {
                foreach (KeyValuePair<string, BaseObject> obj in group.Value)
                {
                    obj.Value.LoadContent();
                }
            }
        }

        #endregion

        #region ISpatialTree Members


        public void LoadFromFile(string asset)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}
